package cn.chenc.framework.dynamic.datasource.aspect;


import cn.chenc.framework.dynamic.datasource.DynamicDataSource;
import cn.chenc.framework.dynamic.datasource.annotation.ChangDataSource;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * 　@description: 动态数据源
 * 　@author secret
 * 　@date 2021/7/21 23:02
 *
 */
@Aspect
@Order(-10)
@Component
public class DataSourceAspect {
    Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);


    public DataSourceAspect() {
    }

    @Pointcut("@annotation(cn.chenc.framework.dynamic.datasource.annotation.ChangDataSource)"
            + "|| @within(cn.chenc.framework.dynamic.datasource.annotation.ChangDataSource)")
    public void dsPointCut() {

    }

    /**
     * 方法执行前进行
     * @param point
     * @throws Exception
     */
    @Before("dsPointCut()")
    public void changeDataSource(JoinPoint point) throws Exception {
        ChangDataSource source = getDataSource(point);
        String name = source.name();
        this.logger.info("change dataSource :" + name);
        if (!DynamicDataSource.checkDataSourceType(name)) {
            throw new Exception("数据源" + name + "不存在，使用默认数据源  ");
        } else {
            //切换数据源
            DynamicDataSource.setDataSourceType(name);
        }
    }

    /**
     * 方法结束后进行
     * @param point
     */
    @AfterReturning("dsPointCut()")
    public void restoreDataSource(JoinPoint point) {
        //方法执行结束后，销毁数据源
        DynamicDataSource.clearDataSourceType();
    }

    /**
     * 获取需要切换的数据源
     */
    public ChangDataSource getDataSource(JoinPoint point)
    {
        MethodSignature signature = (MethodSignature) point.getSignature();
        ChangDataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), ChangDataSource.class);
        if (Objects.nonNull(dataSource))
        {
            return dataSource;
        }

        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), ChangDataSource.class);
    }
}
